package l1j.server.server.templates;

import l1j.server.server.ActionCodes;
import l1j.server.server.GeneralThreadPool;
import l1j.server.server.datatables.SkillsTable;
import l1j.server.server.model.L1Character;
import l1j.server.server.model.L1Object;
import l1j.server.server.model.L1World;
import l1j.server.server.model.Instance.L1MonsterInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.Instance.L1PetInstance;
import l1j.server.server.model.Instance.L1SummonInstance;
import l1j.server.server.model.damage.L1Dmg;
import l1j.server.server.serverpackets.S_EffectLocation;
import l1j.server.server.serverpackets.S_SkillSound;
import l1j.server.server.serverpackets.S_UseAttackSkill;
import l1j.server.server.serverpackets.ServerBasePacket;
import l1j.server.server.utils.Random;

public class WeaponEffect {
	private int _item_id;
	private int _enchant_level_require;

	public int getItemId() {
		return _item_id;
	}

	public int getEnchantLevelRequire() {
		return _enchant_level_require;
	}

	private int _effect_id;
	private boolean _arrowType;
	private int _chance;
	private int _dmg_base;
	private int _dmg_random;
	private int _rate_str;
	private int _rate_dex;
	private int _rate_int;
	private int _rate_con;
	private int _rate_wis;
	private int _rate_cha;
	private int _attr;
	private int _effect_time;
	private int _effect_delay;
	private int _effect_area;
	private int _effect_skill;
	private int _effect_skill_time;

	public WeaponEffect(int item_id, int enchant_level_require, int effect_id,
			boolean arrowType, int chance, int dmg_base, int dmg_random,
			int rate_str, int rate_dex, int rate_int, int rate_con,
			int rate_wis, int rate_cha, int attr, int effect_time,
			int effect_delay, int effect_area, int effect_skill,
			int effect_skill_time) {
		_item_id = item_id;
		_enchant_level_require = enchant_level_require;
		_effect_id = effect_id;
		_arrowType = arrowType;
		_chance = chance;
		_dmg_base = dmg_base;
		_dmg_random = dmg_random;
		_rate_str = rate_str;
		_rate_dex = rate_dex;
		_rate_int = rate_int;
		_rate_con = rate_con;
		_rate_wis = rate_wis;
		_rate_cha = rate_cha;
		_attr = attr;
		_effect_time = effect_time;
		_effect_delay = effect_delay;
		_effect_area = effect_area;
		_effect_skill = effect_skill;
		_effect_skill_time = effect_skill_time;
	}

	public void effect(L1PcInstance pc, L1Character cha) {
		if (!Random.chance100(_chance)) {
			return;
		}
		if (_effect_time <= 1) {
			ServerBasePacket effectPacket;
			if (_arrowType) {
				int[] data = { ActionCodes.ACTION_Attack, 0, _effect_id, 6 };
				effectPacket = new S_UseAttackSkill(pc, cha.getId(),
						cha.getX(), cha.getY(), data, false);
			} else {
				effectPacket = new S_SkillSound(cha.getId(), _effect_id);
			}
			pc.sendPackets(effectPacket);
			pc.broadcastPacket(effectPacket);

			effectDmg(pc, cha);
			
			if (_effect_skill != 0) {
				L1Skills skill = SkillsTable.getInstance().getTemplate(_effect_skill);
				if ((skill != null) && skill.getTarget().equals("buff")) {
					if (cha.canEffectMagic()) { // 凍結状態orカウンターマジック中
						cha.setSkillEffect(_effect_skill,
								_effect_skill_time* 1000);
					}
				}
			}
		} else {
			EffectThread et = new EffectThread(pc, cha);
			GeneralThreadPool.getInstance().execute(et);
		}
	}

	private void effectDmg(L1PcInstance pc, L1Character cha) {
		if (_effect_area > 0) {
			for (L1Object object : L1World.getInstance().getVisibleObjects(cha,
					_effect_area)) {
				if (object == null) {
					continue;
				}
				if (!(object instanceof L1Character)) {
					continue;
				}
				if (object.getId() == pc.getId()) {
					continue;
				}
				if (object.getId() == cha.getId()) { // 攻撃対象は除外
					continue;
				}

				// 攻撃対象がMOBの場合は、範囲内のMOBにのみ当たる
				// 攻撃対象がPC,Summon,Petの場合は、範囲内のPC,Summon,Pet,MOBに当たる
				if (cha instanceof L1MonsterInstance) {
					if (!(object instanceof L1MonsterInstance)) {
						continue;
					}
				}
				if ((cha instanceof L1PcInstance)
						|| (cha instanceof L1SummonInstance)
						|| (cha instanceof L1PetInstance)) {
					if (!((object instanceof L1PcInstance)
							|| (object instanceof L1SummonInstance)
							|| (object instanceof L1PetInstance) || (object instanceof L1MonsterInstance))) {
						continue;
					}
				}
				L1Dmg dmg = L1Dmg.get(true, _attr, pc, (L1Character) object);
				dmg.add(_dmg_base).add(Random.nextInt(_dmg_random))
						.add((_rate_str / 100.0) * pc.getStr())
						.add((_rate_dex / 100.0) * pc.getDex())
						.add((_rate_int / 100.0) * pc.getInt())
						.add((_rate_con / 100.0) * pc.getCon())
						.add((_rate_wis / 100.0) * pc.getWis())
						.add((_rate_cha / 100.0) * pc.getCha())
						.hurtTarget(false);

			}
		}
		L1Dmg dmg = L1Dmg.get(true, _attr, pc, cha);
		dmg.add(_dmg_base).add(Random.nextInt(_dmg_random))
				.add((_rate_str / 100.0) * pc.getStr())
				.add((_rate_dex / 100.0) * pc.getDex())
				.add((_rate_int / 100.0) * pc.getInt())
				.add((_rate_con / 100.0) * pc.getCon())
				.add((_rate_wis / 100.0) * pc.getWis())
				.add((_rate_cha / 100.0) * pc.getCha()).hurtTarget(false);
	}

	private class EffectThread implements Runnable {

		private L1PcInstance _attacker;

		private L1Character _target;

		public EffectThread(L1PcInstance attacker, L1Character target) {
			_attacker = attacker;
			_target = target;
		}

		public void run() {
			for (int i = 0; i < _effect_time; i++) {
				effectDmg(_attacker, _target);
				S_EffectLocation packet = new S_EffectLocation(
						_target.getX(), _target.getY(),_effect_id);
				_attacker.sendPackets(packet);
				_attacker.broadcastPacket(packet);
				try {
					Thread.sleep(_effect_delay);
				} catch (InterruptedException e) {

				}
			}
		}
	}
}
